package com.example.design.sercive;

import com.example.design.ordermanagement.audit.*;
import com.example.design.ordermanagement.command.OrderCommand;
import com.example.design.ordermanagement.command.invoker.OrderCommandInvoker;
import com.example.design.ordermanagement.state.OrderState;
import com.example.design.ordermanagement.state.OrderStateChangeAction;
import com.example.design.pay.facade.PayFacade;
import com.example.design.pojo.Order;
import com.example.design.sercive.inner.OrderServiceInterface;
import com.example.design.tansaction.colleague.AbstractCustomer;
import com.example.design.tansaction.colleague.Buyer;
import com.example.design.tansaction.colleague.Payer;
import com.example.design.tansaction.mediator.Mediator;
import com.example.design.utils.RedisUtils;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.redis.RedisStateMachinePersister;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

//装饰器模式具体构件角色 (pay 方法)
@Service
public class OrderService implements OrderServiceInterface {

    //依赖注入Spring状态机，与状态机进行交互
    @Resource
    private StateMachine<OrderState, OrderStateChangeAction> orderStateMachine;

    //持久化状态机
    @Resource
    private RedisStateMachinePersister<OrderState, OrderStateChangeAction> stateMachineRedisPersister;

    //门面模式门面
    @Resource
    private PayFacade payFacade;

    //命令模式
    @Resource
    private OrderCommand orderCommand;

    //依赖注入RedisUtils，存取订单对象
    @Resource
    private RedisUtils redisUtils;

    @Resource
    private CreateOrderLog createOrderLog;

    @Resource
    private PayOrderLog payOrderLog;

    @Resource
    private SendOrderLog sendOrderLog;

    @Resource
    private ReceiveOrderLog receiveOrderLog;



    @Override
    public Order createOrder(String productId) throws Exception {
        //需要生成全局唯一id
        String orderId = "OID" + productId;
        //创建订单并保存到redis
        Order order = Order.builder().orderId(orderId).productId(productId).orderState(OrderState.ORDER_WAIT_PAY).build();
        redisUtils.set(orderId, order);
        OrderCommandInvoker invoker = new OrderCommandInvoker();
        invoker.invoke(orderCommand,order);
        OrderAuditLog createOrder = createOrderLog.createAuditLog(order.getOrderId(), "createOrder", order.getOrderId());

        return order;
    }



    //支付订单（雷点）

    public Order payOrder(String orderId) {
        //从redis 获取订单对象
        Order order = (Order) redisUtils.get(orderId);
        //包装订单状态变更Message，并附带订单操作PAY_ORDER
        Message<OrderStateChangeAction> message = MessageBuilder
                .withPayload(OrderStateChangeAction.PAY_ORDER)
                .setHeader("order", order)
                .build();
        //将message传递给状态机
        if (changeStateAction(message, order)) {
            return order;
        }
        return null;
    }


    //支付订单支付回调（支付宝）
    public String getPayUrl(String orderId,Float price,Integer payType){
        Order order = (Order) redisUtils.get(orderId);
        order.setPrice(price);
        String pay = payFacade.pay(order, payType);
        OrderAuditLog payOrder = payOrderLog.createAuditLog(order.getOrderId(), "payOrder", order.getOrderId());

        return pay;
    }


    public Order receiveOrder(String orderId) {
        //从redis 获取订单对象
        Order order = (Order) redisUtils.get(orderId);
        //包装订单状态变更Message，并附带订单操作PAY_ORDER
        Message<OrderStateChangeAction> message = MessageBuilder
                .withPayload(OrderStateChangeAction.RECEIVE_ORDER)
                .setHeader("order", order)
                .build();
        //将message传递给状态机
        if (changeStateAction(message, order)) {
            return order;
        }
        OrderAuditLog receiveOrder = receiveOrderLog.createAuditLog(order.getOrderId(), "receiveOrder", order.getOrderId());

        return null;
    }


    public Order sendOrder(String orderId) {
        //从redis 获取订单对象
        Order order = (Order) redisUtils.get(orderId);
        //包装订单状态变更Message，并附带订单操作PAY_ORDER
        Message<OrderStateChangeAction> message = MessageBuilder
                .withPayload(OrderStateChangeAction.SEND_ORDER)
                .setHeader("order", order)
                .build();
        //将message传递给状态机
        if (changeStateAction(message, order)) {
            return order;
        }
        OrderAuditLog sendOrder = sendOrderLog.createAuditLog(order.getOrderId(), "sendOrder", order.getOrderId());

        return null;
    }

    private boolean changeStateAction(Message<OrderStateChangeAction> message, Order order) {
        try {
           //启动状态机
            orderStateMachine.start();
            //从redis 缓存获取状态机，缓存的key 为orderId+"STATE"，这是自定义的，根据喜好来
            stateMachineRedisPersister.restore(orderStateMachine,order.getOrderId()+"STATE");
            //将消息发送listener
            boolean res = orderStateMachine.sendEvent(message);
            //将更改订单状态的状态机存储道redis
            stateMachineRedisPersister.persist(orderStateMachine,order.getOrderId()+"STATE");
            return res;
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            orderStateMachine.stop();
        }
        return false;
    }


    @Resource
    private Mediator mediator;

    public void friendPay(String sourceCustomer, String orderId, String targetCustomer, String payResult, String role) {
        //创建中介者
        Buyer buyer = new Buyer(orderId, mediator,sourceCustomer);
        Payer payer = new Payer(orderId, mediator,sourceCustomer);
        Map<String, AbstractCustomer> map = new HashMap<>();
        map.put("buyer",buyer);
        map.put("payer",payer);
        //将同事类配置到
        Mediator.customerInstances.put(orderId,map);
        if(role.equals("B")) {
            buyer.messageTransfer(orderId, targetCustomer, payResult);
        } else if(role.equals("P")) {
            payer.messageTransfer(orderId,targetCustomer,payResult);
        }
    }


}
